home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Freeware / Miro 1.0 / Miro_Installer.exe / xulrunner / python / psyco / profiler.py < prev    next >
Encoding:
Python Source  |  2007-04-13  |  11.6 KB  |  389 lines

  1. ###########################################################################
  2. #  Psyco profiler (Python part).
  3. #   Copyright (C) 2001-2002  Armin Rigo et.al.
  4.  
  5. """Psyco profiler (Python part).
  6.  
  7. The implementation of the non-time-critical parts of the profiler.
  8. See profile() and full() in core.py for the easy interface.
  9. """
  10. ###########################################################################
  11.  
  12. import _psyco
  13. from support import *
  14. import math, time, types, atexit
  15. now = time.time
  16. try:
  17.     import thread
  18. except ImportError:
  19.     import dummy_thread as thread
  20.  
  21.  
  22. # current profiler instance
  23. current = None
  24.  
  25. # enabled profilers, in order of priority
  26. profilers = []
  27.  
  28. # logger module (when enabled by core.log())
  29. logger = None
  30.  
  31. # a lock for a thread-safe go()
  32. go_lock = thread.allocate_lock()
  33.  
  34. def go(stop=0):
  35.     # run the highest-priority profiler in 'profilers'
  36.     global current
  37.     go_lock.acquire()
  38.     try:
  39.         prev = current
  40.         if stop:
  41.             del profilers[:]
  42.         if prev:
  43.             if profilers and profilers[0] is prev:
  44.                 return    # best profiler already running
  45.             prev.stop()
  46.             current = None
  47.         for p in profilers[:]:
  48.             if p.start():
  49.                 current = p
  50.                 if logger: # and p is not prev:
  51.                     logger.write("%s: starting" % p.__class__.__name__, 5)
  52.                 return
  53.     finally:
  54.         go_lock.release()
  55.     # no profiler is running now
  56.     if stop:
  57.         if logger:
  58.             logger.writefinalstats()
  59.     else:
  60.         tag2bind()
  61.  
  62. atexit.register(go, 1)
  63.  
  64.  
  65. def buildfncache(globals, cache):
  66.     if hasattr(types.IntType, '__dict__'):
  67.         clstypes = (types.ClassType, types.TypeType)
  68.     else:
  69.         clstypes = types.ClassType
  70.     for x in globals.values():
  71.         if isinstance(x, types.MethodType):
  72.             x = x.im_func
  73.         if isinstance(x, types.FunctionType):
  74.             cache[x.func_code] = x, ''
  75.         elif isinstance(x, clstypes):
  76.             for y in x.__dict__.values():
  77.                 if isinstance(y, types.MethodType):
  78.                     y = y.im_func
  79.                 if isinstance(y, types.FunctionType):
  80.                     cache[y.func_code] = y, x.__name__
  81.  
  82. # code-to-function mapping (cache)
  83. function_cache = {}
  84.  
  85. def trytobind(co, globals, log=1):
  86.     try:
  87.         f, clsname = function_cache[co]
  88.     except KeyError:
  89.         buildfncache(globals, function_cache)
  90.         try:
  91.             f, clsname = function_cache[co]
  92.         except KeyError:
  93.             if logger:
  94.                 logger.write('warning: cannot find function %s in %s' %
  95.                              (co.co_name, globals.get('__name__', '?')), 3)
  96.             return  # give up
  97.     if logger and log:
  98.         modulename = globals.get('__name__', '?')
  99.         if clsname:
  100.             modulename += '.' + clsname
  101.         logger.write('bind function: %s.%s' % (modulename, co.co_name), 1)
  102.     f.func_code = _psyco.proxycode(f)
  103.  
  104.  
  105. if PYTHON_SUPPORT:
  106.     # the list of code objects that have been tagged
  107.     tagged_codes = []
  108.     
  109.     def tag(co, globals):
  110.         if logger:
  111.             try:
  112.                 f, clsname = function_cache[co]
  113.             except KeyError:
  114.                 buildfncache(globals, function_cache)
  115.                 try:
  116.                     f, clsname = function_cache[co]
  117.                 except KeyError:
  118.                     clsname = ''  # give up
  119.             modulename = globals.get('__name__', '?')
  120.             if clsname:
  121.                 modulename += '.' + clsname
  122.             logger.write('tag function: %s.%s' % (modulename, co.co_name), 1)
  123.         tagged_codes.append((co, globals))
  124.         _psyco.turbo_frame(co)
  125.         _psyco.turbo_code(co)
  126.  
  127.     def tag2bind():
  128.         if tagged_codes:
  129.             if logger:
  130.                 logger.write('profiling stopped, binding %d functions' %
  131.                              len(tagged_codes), 2)
  132.             for co, globals in tagged_codes:
  133.                 trytobind(co, globals, 0)
  134.             function_cache.clear()
  135.             del tagged_codes[:]
  136.  
  137. else:
  138.     # tagging is impossible, always bind
  139.     tag = trytobind
  140.     def tag2bind():
  141.         pass
  142.  
  143.  
  144.  
  145. class Profiler:
  146.     MemoryTimerResolution = 0.103
  147.  
  148.     def run(self, memory, time, memorymax, timemax):
  149.         self.memory = memory
  150.         self.memorymax = memorymax
  151.         self.time = time
  152.         if timemax is None:
  153.             self.endtime = None
  154.         else:
  155.             self.endtime = now() + timemax
  156.         self.alarms = []
  157.         profilers.append(self)
  158.         go()
  159.     
  160.     def start(self):
  161.         curmem = _psyco.memory()
  162.         memlimits = []
  163.         if self.memorymax is not None:
  164.             if curmem >= self.memorymax:
  165.                 if logger:
  166.                     logger.writememory()
  167.                 return self.limitreached('memorymax')
  168.             memlimits.append(self.memorymax)
  169.         if self.memory is not None:
  170.             if self.memory <= 0:
  171.                 if logger:
  172.                     logger.writememory()
  173.                 return self.limitreached('memory')
  174.             memlimits.append(curmem + self.memory)
  175.             self.memory_at_start = curmem
  176.  
  177.         curtime = now()
  178.         timelimits = []
  179.         if self.endtime is not None:
  180.             if curtime >= self.endtime:
  181.                 return self.limitreached('timemax')
  182.             timelimits.append(self.endtime - curtime)
  183.         if self.time is not None:
  184.             if self.time <= 0.0:
  185.                 return self.limitreached('time')
  186.             timelimits.append(self.time)
  187.             self.time_at_start = curtime
  188.         
  189.         try:
  190.             self.do_start()
  191.         except error, e:
  192.             if logger:
  193.                 logger.write('%s: disabled by psyco.error:' % (
  194.                     self.__class__.__name__), 4)
  195.                 logger.write('    %s' % str(e), 3)
  196.             return 0
  197.         
  198.         if memlimits:
  199.             self.memlimits_args = (time.sleep, (self.MemoryTimerResolution,),
  200.                                    self.check_memory, (min(memlimits),))
  201.             self.alarms.append(_psyco.alarm(*self.memlimits_args))
  202.         if timelimits:
  203.             self.alarms.append(_psyco.alarm(time.sleep, (min(timelimits),),
  204.                                             self.time_out))
  205.         return 1
  206.     
  207.     def stop(self):
  208.         for alarm in self.alarms:
  209.             alarm.stop(0)
  210.         for alarm in self.alarms:
  211.             alarm.stop(1)   # wait for parallel threads to stop
  212.         del self.alarms[:]
  213.         if self.time is not None:
  214.             self.time -= now() - self.time_at_start
  215.         if self.memory is not None:
  216.             self.memory -= _psyco.memory() - self.memory_at_start
  217.  
  218.         try:
  219.             self.do_stop()
  220.         except error:
  221.             return 0
  222.         return 1
  223.  
  224.     def check_memory(self, limit):
  225.         if _psyco.memory() < limit:
  226.             return self.memlimits_args
  227.         go()
  228.  
  229.     def time_out(self):
  230.         self.time = 0.0
  231.         go()
  232.  
  233.     def limitreached(self, limitname):
  234.         try:
  235.             profilers.remove(self)
  236.         except ValueError:
  237.             pass
  238.         if logger:
  239.             logger.write('%s: disabled (%s limit reached)' % (
  240.                 self.__class__.__name__, limitname), 4)
  241.         return 0
  242.  
  243.  
  244. class FullCompiler(Profiler):
  245.  
  246.     def do_start(self):
  247.         _psyco.profiling('f')
  248.  
  249.     def do_stop(self):
  250.         _psyco.profiling('.')
  251.  
  252.  
  253. class RunOnly(Profiler):
  254.  
  255.     def do_start(self):
  256.         _psyco.profiling('n')
  257.  
  258.     def do_stop(self):
  259.         _psyco.profiling('.')
  260.  
  261.  
  262. class ChargeProfiler(Profiler):
  263.  
  264.     def __init__(self, watermark, parentframe):
  265.         self.watermark = watermark
  266.         self.parent2 = parentframe * 2.0
  267.         self.lock = thread.allocate_lock()
  268.  
  269.     def init_charges(self):
  270.         _psyco.statwrite(watermark = self.watermark,
  271.                          parent2   = self.parent2)
  272.  
  273.     def do_stop(self):
  274.         _psyco.profiling('.')
  275.         _psyco.statwrite(callback = None)
  276.  
  277.  
  278. class ActiveProfiler(ChargeProfiler):
  279.  
  280.     def active_start(self):
  281.         _psyco.profiling('p')
  282.  
  283.     def do_start(self):
  284.         self.init_charges()
  285.         self.active_start()
  286.         _psyco.statwrite(callback = self.charge_callback)
  287.  
  288.     def charge_callback(self, frame, charge):
  289.         tag(frame.f_code, frame.f_globals)
  290.  
  291.  
  292. class PassiveProfiler(ChargeProfiler):
  293.  
  294.     initial_charge_unit   = _psyco.statread('unit')
  295.     reset_stats_after     = 120      # half-lives (maximum 200!)
  296.     reset_limit           = initial_charge_unit * (2.0 ** reset_stats_after)
  297.  
  298.     def __init__(self, watermark, halflife, pollfreq, parentframe):
  299.         ChargeProfiler.__init__(self, watermark, parentframe)
  300.         self.pollfreq = pollfreq
  301.         # self.progress is slightly more than 1.0, and computed so that
  302.         # do_profile() will double the change_unit every 'halflife' seconds.
  303.         self.progress = 2.0 ** (1.0 / (halflife * pollfreq))
  304.  
  305.     def reset(self):
  306.         _psyco.statwrite(unit = self.initial_charge_unit, callback = None)
  307.         _psyco.statreset()
  308.         if logger:
  309.             logger.write("%s: resetting stats" % self.__class__.__name__, 1)
  310.  
  311.     def passive_start(self):
  312.         self.passivealarm_args = (time.sleep, (1.0 / self.pollfreq,),
  313.                                   self.do_profile)
  314.         self.alarms.append(_psyco.alarm(*self.passivealarm_args))
  315.  
  316.     def do_start(self):
  317.         tag2bind()
  318.         self.init_charges()
  319.         self.passive_start()
  320.  
  321.     def do_profile(self):
  322.         _psyco.statcollect()
  323.         if logger:
  324.             logger.dumpcharges()
  325.         nunit = _psyco.statread('unit') * self.progress
  326.         if nunit > self.reset_limit:
  327.             self.reset()
  328.         else:
  329.             _psyco.statwrite(unit = nunit, callback = self.charge_callback)
  330.         return self.passivealarm_args
  331.  
  332.     def charge_callback(self, frame, charge):
  333.         trytobind(frame.f_code, frame.f_globals)
  334.  
  335.  
  336. class ActivePassiveProfiler(PassiveProfiler, ActiveProfiler):
  337.  
  338.     def do_start(self):
  339.         self.init_charges()
  340.         self.active_start()
  341.         self.passive_start()
  342.  
  343.     def charge_callback(self, frame, charge):
  344.         tag(frame.f_code, frame.f_globals)
  345.  
  346.  
  347.  
  348. #
  349. # we register our own version of sys.settrace(), sys.setprofile()
  350. # and thread.start_new_thread().
  351. #
  352.  
  353. def psyco_settrace(*args, **kw):
  354.     "This is the Psyco-aware version of sys.settrace()."
  355.     result = original_settrace(*args, **kw)
  356.     go()
  357.     return result
  358.  
  359. def psyco_setprofile(*args, **kw):
  360.     "This is the Psyco-aware version of sys.setprofile()."
  361.     result = original_setprofile(*args, **kw)
  362.     go()
  363.     return result
  364.  
  365. def psyco_thread_stub(callable, args, kw):
  366.     _psyco.statcollect()
  367.     if kw is None:
  368.         return callable(*args)
  369.     else:
  370.         return callable(*args, **kw)
  371.  
  372. def psyco_start_new_thread(callable, args, kw=None):
  373.     "This is the Psyco-aware version of thread.start_new_thread()."
  374.     return original_start_new_thread(psyco_thread_stub, (callable, args, kw))
  375.  
  376. original_settrace         = sys.settrace
  377. original_setprofile       = sys.setprofile
  378. original_start_new_thread = thread.start_new_thread
  379. sys.settrace            = psyco_settrace
  380. sys.setprofile          = psyco_setprofile
  381. if PYTHON_SUPPORT:
  382.     thread.start_new_thread = psyco_start_new_thread
  383.     # hack to patch threading._start_new_thread if the module is
  384.     # already loaded
  385.     if (sys.modules.has_key('threading') and
  386.         hasattr(sys.modules['threading'], '_start_new_thread')):
  387.         sys.modules['threading']._start_new_thread = psyco_start_new_thread
  388.